package com.woniuxy.project115.kaer.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.woniuxy.project115.kaer.commons.util.MD5Util;
import com.woniuxy.project115.kaer.commons.util.SMSUtil;
import com.woniuxy.project115.kaer.user.dto.LoginDto;
import com.woniuxy.project115.kaer.user.dto.UserInfoDto;
import com.woniuxy.project115.kaer.user.entity.LoginLog;
import com.woniuxy.project115.kaer.user.entity.ScoreLog;
import com.woniuxy.project115.kaer.user.entity.UserInfo;
import com.woniuxy.project115.kaer.user.form.RealNameAuthForm;
import com.woniuxy.project115.kaer.user.mapper.LoginLogMapper;
import com.woniuxy.project115.kaer.user.mapper.ScoreLogMapper;
import com.woniuxy.project115.kaer.user.mapper.UserInfoMapper;
import com.woniuxy.project115.kaer.user.param.AccountRegisterParam;
import com.woniuxy.project115.kaer.user.param.CodeRegisterParam;
import com.woniuxy.project115.kaer.user.param.ScoreChangeParam;
import com.woniuxy.project115.kaer.user.service.UserInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.project115.kaer.user.util.RedisKey;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author fyy
 * @since 2025年02月17日
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private LoginLogMapper loginLogMapper;
    @Resource
    private ScoreLogMapper scoreLogMapper;


    @Override
    public void accountRegister(AccountRegisterParam arp) throws Exception {
        final QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("user_phone",arp.getUserPhone());
        //判断用户是否存在
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        if (userInfo!= null){
            throw new Exception("用户已存在");
        }
        //账号没被注册，可以注册
        final UserInfo userInfo1 = new UserInfo();
        userInfo1.setUserPhone(arp.getUserPhone());
        userInfo1.setUserPass(MD5Util.md5(arp.getUserPass(), arp.getUserPhone()));
        userInfo1.setNickName(arp.getNickName());
        userInfo1.setEmail(arp.getEmail());
        userInfo1.setRealState("未实名");
        userInfo1.setCreateTime(LocalDateTime.now());
        userInfo1.setScore(0);
        userInfo1.setState(0);
        userInfoMapper.insert(userInfo1);
    }

    @Override
    public void sendRegisterCode(String phone) throws Exception {
        //1.判断是否在60秒内发送过验证码
        if (stringRedisTemplate.hasKey(RedisKey.REGISTER_CODE_STATE(phone))){
            throw new Exception("请勿频繁发送验证码");
        }
        //1.去重判断
        final QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("user_phone",phone);
        //判断用户是否存在
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        if (userInfo!= null){
            throw new Exception("该手机号已经注册");
        }
        //2.调用第三方接口生成验证码
        final String code = SMSUtil.sendCode(phone);
        //3.保存验证码到redis
        stringRedisTemplate.opsForValue().set(RedisKey.REGISTER_CODE_KEY(phone),code,300, TimeUnit.SECONDS);
        //4.保存一个键值对，表示该手机号已发送过验证码，防止频繁发送验证码
        stringRedisTemplate.opsForValue().set(RedisKey.REGISTER_CODE_STATE(phone),"1",60, TimeUnit.SECONDS);
    }

    @Override
    public void codeRegister(CodeRegisterParam bean) throws Exception {
        //1.判断验证码是否正确
        final String code = stringRedisTemplate.opsForValue().get(RedisKey.REGISTER_CODE_KEY(bean.getUserPhone()));
        if (!code.equals(bean.getCode())||code==null){
            throw new Exception("验证码错误或已过期");
        }
        //判断手机号是否已注册
        final QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("user_phone",bean.getUserPhone());
        //判断用户是否存在
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        if (userInfo!= null){
            throw new Exception("该手机号已经注册");
        }
        //2.注册用户
        final UserInfo userInfo1 = new UserInfo();
        userInfo1.setUserPhone(bean.getUserPhone());
        userInfo1.setUserPass(MD5Util.md5(bean.getUserPass(), bean.getUserPhone()));
        userInfo1.setNickName(bean.getNickName());
        userInfo1.setEmail(bean.getEmail());
        userInfo1.setRealState("未实名");
        userInfo1.setCreateTime(LocalDateTime.now());
        userInfo1.setScore(0);
        userInfo1.setState(0);
        userInfoMapper.insert(userInfo1);
        //3.删除redis中的验证码
        stringRedisTemplate.delete(RedisKey.REGISTER_CODE_KEY(bean.getUserPhone()));
        //4.删除redis中的验证码发送状态
        stringRedisTemplate.delete(RedisKey.REGISTER_CODE_STATE(bean.getUserPhone()));
    }

    @Override
    public void sendLoginCode(String phone) throws Exception {
        //判断是否有这个手机号
        final QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("user_phone",phone);
        //判断用户是否存在
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        if (userInfo == null){
            throw new Exception("该手机号未注册");
        }
        //存在账号，发送验证码
        final String code = SMSUtil.sendCode(phone);
        //保存验证码到redis
        stringRedisTemplate.opsForValue().set(RedisKey.LOGIN_CODE_KEY(phone),code,300, TimeUnit.SECONDS);
        //保存一个键值对，表示该手机号已发送过验证码，防止频繁发送验证码
        stringRedisTemplate.opsForValue().set(RedisKey.LOGIN_CODE_STATE(phone),"1",60, TimeUnit.SECONDS);
    }

    @Override
    public LoginDto smsLogin(String phone, String code) throws Exception {
        //1.判断验证码是否正确
        final String redisCode = stringRedisTemplate.opsForValue().get(RedisKey.LOGIN_CODE_KEY(phone));
        if (!redisCode.equals(code) || redisCode == null){
            throw new Exception("验证码错误或已过期");
        }
        //2.判断手机号是否已注册
        final QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("user_phone",phone);
        //判断用户是否存在
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        if (userInfo == null){
            throw new Exception("该手机号未注册");
        }
        //判断账号是否被禁用
        if (userInfo.getState() != 0){
            throw new Exception("该账号状态异常，请联系客服");
        }
        //3.登录成功，删除redis中的验证码
        stringRedisTemplate.delete(RedisKey.LOGIN_CODE_KEY(phone));
        //4.删除redis中的验证码发送状态
        stringRedisTemplate.delete(RedisKey.LOGIN_CODE_STATE(phone));
        return BeanUtil.toBean(userInfo,LoginDto.class);
    }

    @Override
    public LoginDto accountLogin(String account, String password, HttpServletRequest req) throws Exception {
        //1.判断账号是否存在
        final QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("user_phone",account);
        //判断用户是否存在
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        if (userInfo == null){
            throw new Exception("账号或密码错误");
        }
        //2.判断密码是否正确
        if (!MD5Util.md5(password, userInfo.getUserPhone()).equals(userInfo.getUserPass())){
            throw new Exception("账号或密码错误");
        }
        //3.判断账号是否被禁用
        if (userInfo.getState() != 0){
            throw new Exception("该账号状态异常，请联系客服");
        }
        //添加登录日志
        final LoginLog loginLog = new LoginLog();
        loginLog.setUserId(userInfo.getUserId());
        loginLog.setLoginIp(req.getRemoteAddr());
        loginLog.setLoginTime(LocalDateTime.now());
        loginLogMapper.insert(loginLog);

        final LoginDto loginDto = BeanUtil.toBean(userInfo, LoginDto.class);
        loginDto.setRole("普通用户");
        return loginDto;
    }

    @Override
    public void scoreChange(ScoreChangeParam bean) throws Exception {
        //1.判断用户是否存在
        final QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("user_id",bean.getUserId());
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        if (userInfo == null){
            throw new Exception("用户不存在");
        }
        //判断用户是加分还是减分
        //记录日志
        ScoreLog scoreLog = new ScoreLog();
        scoreLog.setUserId(bean.getUserId());
        scoreLog.setScoreNum(bean.getScore());
        if (bean.getType().equals("加")){
            //加分
            userInfo.setScore(userInfo.getScore() + bean.getScore());
            userInfoMapper.updateById(userInfo);
            scoreLog.setType("返还");
        }
        //减分,判断积分是否足够
        if (bean.getType().equals("减")){
            //减分
            if (userInfo.getScore() < bean.getScore()){
                throw new Exception("积分不足");
            }
            userInfo.setScore(userInfo.getScore() - bean.getScore());
            userInfoMapper.updateById(userInfo);
            scoreLog.setType("扣除");
        }
        scoreLog.setTime(LocalDateTime.now());
        scoreLogMapper.insert(scoreLog);
    }

    @Override
    public void realNameAuth(RealNameAuthForm raf) throws Exception {
        //1.判断用户是否存在
        final QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("user_id",raf.getUserId());
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        if (userInfo == null){
            throw new Exception("用户不存在");
        }
        //2.判断用户是否已经实名
        if (userInfo.getRealState().equals("已实名")){
            throw new Exception("用户已实名");
        }
        //3.实名认证
        userInfo.setRealName(raf.getRealName());
        userInfo.setCardId(raf.getCardId());
        userInfo.setRealState("已实名");
        userInfoMapper.updateById(userInfo);
    }

    @Override
    public List<UserInfoDto> getAllUserInfo() {
        //查询所有用户信息
        final QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.ne("state", 3);
        final List<UserInfo> userInfoList = userInfoMapper.selectList(wrapper);
        //循环转换成dto
        final ArrayList<UserInfoDto> list = new ArrayList<>();
        for (UserInfo userInfo : userInfoList){
            UserInfoDto userInfoDto = BeanUtil.toBean(userInfo,UserInfoDto.class);
            list.add(userInfoDto);
        }
        return list;
    }

    @Override
    public void banUser(Integer userId,Integer state) throws Exception {
        //判断账号状态是否正常
        final QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("user_id",userId);
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        if (userInfo == null){
            throw new Exception("用户不存在");
        }
        if (userInfo.getState() == 3){
            throw new Exception("该账号状态异常，请联系客服");
        }
        //修改账号状态
        userInfo.setState(state);
        userInfoMapper.updateById(userInfo);
    }

    @Override
    public UserInfoDto getUserById(Integer userId)throws Exception {
        //查询用户信息
        final QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("user_id",userId);
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        if (userInfo == null){
            throw new Exception("用户不存在");
        }
        return BeanUtil.toBean(userInfo,UserInfoDto.class);
    }

}
